package com.ruoyi.business.config;

import com.ruoyi.common.exception.ServiceException;
import feign.FeignException;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

/**
 * Feign错误解码器
 * 
 * 错误处理流程：
 * 1. 接收Feign调用异常
 * 2. 解析HTTP状态码
 * 3. 根据状态码分类处理错误
 * 4. 转换为业务异常并记录日志
 * 
 * 使用此解码器替代FallbackFactory，统一处理所有Feign调用异常
 */
@Configuration
@Slf4j
public class FeignErrorDecoder implements ErrorDecoder {

    /**
     * 解码Feign调用异常
     * 
     * @param methodKey 调用的方法标识
     * @param response 响应对象
     * @return 处理后的异常
     */
    @Override
    public Exception decode(String methodKey, Response response) {
        // 步骤1: 获取HTTP状态码
        HttpStatus responseStatus = HttpStatus.valueOf(response.status());
        
        // 步骤2: 处理服务器错误（5xx）
        if (responseStatus.is5xxServerError()) {
            String errorMessage = String.format("远程服务[%s]内部错误: %s", 
                    extractServiceName(response.request().url()), 
                    response.reason());
            log.error(errorMessage);
            return new ServiceException("远程服务暂时不可用，请稍后再试");
        } 
        
        // 步骤3: 处理客户端错误（4xx）
        else if (responseStatus.is4xxClientError()) {
            return handleClientError(methodKey, response, responseStatus);
        }
        
        // 步骤4: 处理其他未分类的错误
        log.error("未知远程调用错误: {} - 状态码: {}", methodKey, response.status());
        return FeignException.errorStatus(methodKey, response);
    }
    
    /**
     * 处理客户端错误（4xx状态码）
     * 
     * @param methodKey 调用的方法标识
     * @param response 响应对象
     * @param status HTTP状态码
     * @return 处理后的异常
     */
    private Exception handleClientError(String methodKey, Response response, HttpStatus status) {
        String url = response.request().url();
        String serviceName = extractServiceName(url);
        
        // 处理常见的客户端错误
        switch (status) {
            case NOT_FOUND:
                log.error("远程接口不存在: {} - {}", serviceName, url);
                return new ServiceException("请求的接口不存在");
                
            case UNAUTHORIZED:
                log.error("远程服务未授权访问: {} - {}", serviceName, url);
                return new ServiceException("未授权的访问");
                
            case BAD_REQUEST:
                log.error("远程服务请求参数错误: {} - {}", serviceName, url);
                return new ServiceException("请求参数错误");
                
            case FORBIDDEN:
                log.error("远程服务拒绝访问: {} - {}", serviceName, url);
                return new ServiceException("没有权限访问该服务");
                
            default:
                log.error("远程调用客户端错误: {} - 状态码: {} - 原因: {}", 
                        methodKey, status.value(), response.reason());
                return new ServiceException("请求远程服务失败");
        }
    }
    
    /**
     * 从URL中提取服务名称
     * 
     * @param url 请求URL
     * @return 服务名称
     */
    private String extractServiceName(String url) {
        // 简单提取域名或服务标识
        if (url == null) {
            return "unknown";
        }
        
        // 移除协议部分
        String withoutProtocol = url.replaceFirst("^(http|https)://", "");
        // 提取域名部分
        int pathStart = withoutProtocol.indexOf('/');
        if (pathStart > 0) {
            return withoutProtocol.substring(0, pathStart);
        }
        return withoutProtocol;
    }
} 